#ifndef _SOCK_H_
#define _SOCK_H_

#ifdef WIN32
#include <windows.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#endif

#include <string.h>

#ifndef WIN32
#define INVALID_SOCKET -1
typedef socklen_t ADDRLEN_TYPE;
typedef int SOCKET;
#else
typedef int ADDRLEN_TYPE;
#endif

#define MAX_PACKET_SIZE 130000

/************************************************************************/
/* Provides creating sockets connections between servers and clients    */
/************************************************************************/
class Socket {

public:
	
	/************************************************************************/
	/* Creates socket instance                                              */
	/************************************************************************/
	Socket(int addressFamily = AF_INET, int type = SOCK_STREAM, int protocol = IPPROTO_TCP);

	/************************************************************************/
	/* Destroys socket instance                                             */
	/************************************************************************/
	virtual ~Socket();

	/************************************************************************/
	/* Returns ip address											*/
	/************************************************************************/
	const char * getIpAddress() const;

	/************************************************************************/
	/* Sets ip address                                             */
	/************************************************************************/
	void setIpAddress(const char * ip);

	/************************************************************************/
	/* Sets socket's descriptor                                             */
	/************************************************************************/
	void setSockData(SOCKET sockData);

	/************************************************************************/
	/* Sends data to connected socket										*/
	/************************************************************************/
	int sendData(const char * data, int sendLen, int flags = 0);

	/************************************************************************/
	/* Receives data from connected socket                                  */
	/************************************************************************/
	int receiveData(char * data, int receiveLen, int flags = /*MSG_WAITALL*/0, bool reallocMemory = false);

	/************************************************************************/
	/* Close assigned connection                                            */
	/************************************************************************/
	void closeConnection();

protected:

	/************************************************************************/
	/* Address family                                                       */
	/************************************************************************/
	int addressFamily;

	/************************************************************************/
	/* Transport type														*/
	/************************************************************************/
	int type;

	/************************************************************************/
	/* Transport protocol                                                   */
	/************************************************************************/
	int protocol;

	/************************************************************************/
	/* Socket descriptor													*/
	/************************************************************************/
	SOCKET sockData;

	/************************************************************************/
	/* IP address                                                  */
	/************************************************************************/
	char * ip;

private:

	/************************************************************************/
	/* Whether socket API initialized                                       */
	/************************************************************************/
	static bool isInit;

	/************************************************************************/
	/* Initializes socket API                                               */
	/************************************************************************/
	static bool initialize();

	/************************************************************************/
	/* Deinitializes socket API                                             */
	/************************************************************************/
	static void deInitialize();
};

#endif //_SOCK_H_
